package com.ruoyi.web.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.enums.DateFormatEnum;
import com.ruoyi.common.enums.PayDescTxtEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ConvertUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.web.domain.pay.CreateOrderVO;
import com.ruoyi.web.domain.pay.CreatePayReqVO;
import com.ruoyi.web.domain.user.vo.LoginVo;
import com.ruoyi.web.entity.ApiBankConfig;
import com.ruoyi.web.entity.ApiCashFlow;
import com.ruoyi.web.entity.pay.*;
import com.ruoyi.web.entity.pay.response.CreatePayResponse;
import com.ruoyi.web.entity.User;
import com.ruoyi.web.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 用户 业务层处理
 * 
 * @author ruoyi
 */
@Service
public class PayServiceImpl implements ApiPayService
{
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ApiUserService apiUserService;

    @Autowired
    private IApiCashFlowService apiCashFlowService;

    @Autowired
    private WeChatPayService weChatPayService;

    @Autowired
    private IApiBankConfigService apiBankConfigService;

    /**
     * 校验支付项有效性
     */
    public CreateOrderVO verifyBank(CreatePayReqVO wxPayReqVO){
        Long userId = wxPayReqVO.getUserId();
        LoginVo loginVo = new LoginVo();
        loginVo.setUserId(userId);
        User user = apiUserService.selectUserBy(loginVo);
        if(user == null){
            throw new ServiceException("用户不存在");
        }

        // 根据bankId查询金额
        ApiBankConfig apiBank = apiBankConfigService.selectApiBackConfigById(wxPayReqVO.getBankId());
        if(apiBank == null){
            throw new ServiceException("查询不到商品信息");
        }

        // 根据类型区分是什么
        Integer opType = wxPayReqVO.getOpType();

        if(opType == 1){
            // TODO 判断是否是否有首冲
        }else if(opType == 2){
            // TODO 是否购买过会员, 续费时间....
        }
        CreateOrderVO orderVO = new CreateOrderVO();
        orderVO.setUuid(user.getUuid());
        orderVO.setAmount(ConvertUtils.toInt(apiBank.getRealAmount()));// 根据bankId查询金额
        orderVO.setUserId(userId);
        orderVO.setRealIp(wxPayReqVO.getRealIp());
        orderVO.setBankId(wxPayReqVO.getBankId());
        orderVO.setOpType(opType);
        orderVO.setTradeType(wxPayReqVO.getTradeType());
        orderVO.setUuid(user.getUuid());

        // 扩展字段
        PayOrderExtend extend = new PayOrderExtend();
        extend.setUid(userId);
        orderVO.setExtend(JSON.toJSONString(extend));

        return orderVO;
    }

    /**
     * 创建微信通用订单
     * @param wxPayReqVO 请求对象
     * @return CreatePayResponse
     */
    @Override
    public CreatePayResponse traderWxPay(CreatePayReqVO wxPayReqVO) {

        // 如果验证成功之后请求微信创建订单
        CreateOrderVO verifyOrder = verifyBank(wxPayReqVO);

        String orderId = constructTradeNo();
        verifyOrder.setOrderId(orderId);
        String descTxt = PayDescTxtEnum.getTypeByIdentify(verifyOrder.getTradeType());
        verifyOrder.setDescTxt("金币充值:" + orderId + descTxt);

        // 创建微信订单
        CreatePayResponse payResponse = weChatPayService.getWxPayCommonResponse(
                verifyOrder.getTradeType(), orderId, wxPayReqVO.getRealIp(), descTxt, verifyOrder.getAmount(), verifyOrder.getUuid()
        );

        payResponse.setOrderId(orderId);

        // 创建流水记录
        createOrder(verifyOrder);

        return payResponse;
    }

    /**
     * 创建订单记录
     * @param orderVO 请求对象
     * @return CreatePayResponse
     */
    public void createOrder(CreateOrderVO orderVO) {
        Long shopId = orderVO.getBankId();
        Long userId = orderVO.getUserId();
        Integer amount = orderVO.getAmount();
        Integer opType = orderVO.getOpType();
        Integer tradeType = orderVO.getTradeType();

        // TODO 订单号
        ApiCashFlow cashFlow = new ApiCashFlow();
        cashFlow.setOrderId(orderVO.getOrderId());
        cashFlow.setUserId(userId);
        cashFlow.setAmount(amount);
        cashFlow.setOpType(opType);
        cashFlow.setDescTxt(orderVO.getDescTxt());
        cashFlow.setBankId(shopId);
        cashFlow.setTradeType(tradeType);

//        cashFlow.setExtend(extend); // TODO 扩展

        Integer insertRes = apiCashFlowService.insertApiCashFlow(cashFlow);
        if(insertRes <= 0){
            throw new ServiceException("购买失败");
        }

//        return cashFlow.getOrderId();
    }


    /**
     * 支付回调状态
     * @param resultMap void
     */
    @Override
    public void finishV2Order(Map<String, String> resultMap) {

        Integer totalFee = ConvertUtils.toInt(resultMap.get("total_fee")); //分
        String orderId = resultMap.get("out_trade_no"); // 自己的订单号
        String transactionId = resultMap.get("transaction_id"); // 三方订单号

        // 成功在处理
        // 查询订单是否已经支付完
        ApiCashFlow apiCashFlow = new ApiCashFlow();
        apiCashFlow.setOrderId(orderId);
        apiCashFlow.setStatus(0);
        List<ApiCashFlow> cashFlowList = apiCashFlowService.selectApiCashFlowList(apiCashFlow);
        if(!CollectionUtils.isEmpty(cashFlowList)){

            ApiCashFlow cashFlow = cashFlowList.get(0);
            // 判断金额 && 更新数据
            if(totalFee.equals(cashFlow.getAmount())){
                apiCashFlow.setStatus(1);
                apiCashFlow.setId(cashFlow.getId());
                apiCashFlow.setTransactionId(transactionId);
                apiCashFlow.setPayTime(new Date());
                int flow = apiCashFlowService.updateApiCashFlow(apiCashFlow);
                if(flow > 0){
                    // TODO 在去相关的操作
                }
            }

        }
    }


    private static Random random = new Random();

    public static synchronized String constructTradeNo() {
        String tradeNo = DateUtils.convertDateFormat(new Date(), DateFormatEnum.FULL_SECOND);
        for (int index = 0; index < 5; index++) {
            tradeNo = tradeNo + random.nextInt(10);
        }

        return tradeNo;
    }

}
